
#include "io_epoll.h"
#include "io_reuse_module.h"
#include <cstdint>
#include <cstdio>
#include <sys/epoll.h>
#include <vector>

std::shared_ptr<IoReuseModuleImpl> IoEpollFactory::CreateModule()
{
    auto ptr = std::make_shared<IoEpoll>();
    return ptr;
}

IoEpoll::IoEpoll(int size)
{
    m_epoll_fd = epoll_create(size);
    m_index = 1;
}

IoEpoll::~IoEpoll()
{

}

int IoEpoll::AddEpollEvent(int description, struct epoll_event & event) const
{
    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, description, &event);
    return result;
}

int IoEpoll::ModEpollEvent(int description, struct epoll_event & event) const
{
    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, description, &event);
    return result;
}

int IoEpoll::DelEpollEvent(int description) const
{
    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, description, NULL);
    return result;
}

int IoEpoll::EpollWait(std::vector<struct epoll_event> & epoll_event_vec, int wait_time) const
{
    int size = epoll_wait(m_epoll_fd, &(*epoll_event_vec.begin()), epoll_event_vec.size(), wait_time);
    return size;
}

int IoEpoll::WaitEvent(std::vector<struct EventData> & trigger_data, int wait_time)
{
    std::vector<struct epoll_event> event_vec(m_socket_map.size() + 1);
    int size = EpollWait(event_vec, wait_time);
    for (int index = 0; index < size; index++)
    {
        auto & event = event_vec.at(index);
        EventData event_data{};
        event_data.events = ((event.events & EPOLLIN ? EmIoIn : 0)  | (event.events & EPOLLOUT ? EmIoOut : 0) | (event.events & EPOLLERR ? EmIoErr : 0) | (event.events & EPOLLRDHUP ? EmIoRdHup : 0));
        event_data.id     = event.data.u64;

        trigger_data.push_back(event_data);
    }
    return size;
}

int64_t IoEpoll::AddEvent(int description, int  event)
{ 
    struct epoll_event epoll_event_data;
    int64_t index = m_index++;
    epoll_event_data.data.u64 = index;
    epoll_event_data.events   = 0;
    if (event & EmIoIn)
    { 
        epoll_event_data.events |= EPOLLIN;
    }
    if (event & EmIoOut)
    { 
        epoll_event_data.events |= EPOLLOUT;
    }
    if (event & EmIoErr)
    { 
        epoll_event_data.events |= EPOLLERR;
    }
    if (event & EmIoRdHup)
    { 
        epoll_event_data.events |= EPOLLRDHUP; 
    }
    if (event & EmIoOneShot)
    { 
        epoll_event_data.events |= EPOLLONESHOT;
    }
    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, description, &epoll_event_data);
    if (result == 0)
    {
        m_socket_map[index]  = description;
    }
    return result == 0 ? index : -1; 
}

int64_t IoEpoll::ModEvent(int64_t id, int event)
{
    auto iter = m_socket_map.find(id);
    if (iter == m_socket_map.end())
    {
        return -1;
    }
    struct epoll_event epoll_event_data {};
    epoll_event_data.data.u64  = id;
    epoll_event_data.events    = 0;
    if (event & EmIoIn)
    { 
        epoll_event_data.events |= EPOLLIN;
    }
    if (event & EmIoOut)
    { 
        epoll_event_data.events |= EPOLLOUT;
    }
    if (event & EmIoErr)
    { 
        epoll_event_data.events |= EPOLLERR;
    }
    if (event & EmIoRdHup)
    { 
        epoll_event_data.events |= EPOLLRDHUP; 
    }
    if (event & EmIoOneShot)
    { 
        epoll_event_data.events |= EPOLLONESHOT;
    }
    int result = epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, iter->second, &epoll_event_data);
    return result == 0 ? 0 : -1;
}

int64_t IoEpoll::DelEvent(int64_t id)
{ 
    auto iter = m_socket_map.find(id);
    if (iter != m_socket_map.end())
    { 
        epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, iter->second, nullptr);
        m_socket_map.erase(iter);
    }
    return 0;
}

